package sneuro;

public class SNeuro implements Neuronet{
  public double widthMatrix[][];
  private double teach;
  private int countOfInput;
  public int getCountOfInput () {return countOfInput;}
  private int countOfOutput;
  public int getCountOfOutput () {return countOfOutput;}
  private Nstatus status;

  public Nstatus getStatus(){
    return status;
  }

  public SNeuro(int countOfInput, int countOfOutput){
    this.countOfInput = countOfInput;
    this.countOfOutput = countOfOutput;
    widthMatrix = new double[countOfInput][countOfOutput];
    reset() ;   
  }

  public final static long MAXITERATION = 100000;
  public final static long STEPITERATION = 10000;
  public final static double TEACHVALUE = 0.5;
  public final static double BETACOUNTER = 0.3;
  public final static double INCREASETEACHPARAMETER = 0.5;
  public final static double CORRECTION_VALUE = 0.01;

  private double mult;
  public Nstatus train(TrainData traindata){
    mult = traindata.mult;
    double [][] inputs = traindata.inputs;
    int [][] results = traindata.results;
    long startTime = System.currentTimeMillis();
    int iteration = 0;
    int totalIteration=0;
    teach=TEACHVALUE;
    int commonError = 0 ;
    do{
      commonError=0;
      // for each piece of input data
      for (int k=0;k< inputs.length; k++){
        // get result !
        int betaResult[] = result(inputs[k]);
        // correction
        for (int i=0; i<countOfInput; i++){
          for (int j=0;j<countOfOutput;j++)
            widthMatrix[i][j]=widthMatrix[i][j]+teach*inputs[k][i]*(results[k][j]-betaResult[j]);
        }
        // get common error
        for (int j=0;j<countOfOutput;j++)
          commonError+=Math.abs(results[k][j]-betaResult[j]);
      }
      iteration++;
      totalIteration++;
      if (iteration>STEPITERATION){
        teach+=INCREASETEACHPARAMETER;
        iteration=0;
      }
      // we cannot teach...
      if (totalIteration>MAXITERATION){
        status = new Nstatus(false, 0, "Standup failed, too much time");
        return status;
      }
    } while (commonError!=0);
    // done! just return proper status
    status = new Nstatus(true, System.currentTimeMillis()-startTime, "Good");
    return status;
  }

  public void reset(){
    // just clear status;
    status = new Nstatus();
    for (int i=0; i<countOfInput; i++)
      for (int j=0; j<countOfOutput;j++)
       widthMatrix[i][j]=-0.5;
    teach=TEACHVALUE;
  }

  public int[] result(double [] input){
    int result[] = new int[countOfOutput];
    for (int j=0; j<countOfOutput; j++){
      double sum=0;
      for (int i=0; i<countOfInput; i++)
        sum += widthMatrix[i][j]*input[i];
      // KOHANNEN's function      
      sum += mult;
      if (sum>0)
        result[j]=1;
      else
        result[j]=0;
    }
    return result;
  }
  
  public void correction (double[] inputs, int [] offset) {
    for (int i=0; i<countOfInput; i++){
          for (int j=0;j<countOfOutput;j++)
            widthMatrix[i][j]=widthMatrix[i][j]+teach*inputs[i]*(offset[j]);
        }
    teach += CORRECTION_VALUE;
  }
}
